/*
    扫描可用的 AP
 */

#include "scan.h"
#include "string.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_log.h"
#include "esp_event.h"
#include "nvs_flash.h"

#define SCAN_LIST_SIZE      10              /* 驱动程序可以填充的最大扫描列表条目数 */

static const char *TAG = "scan";            /* LOG 日志 */

/* AP 认证模式 */
static void print_auth_mode(int authmode)
{
    switch (authmode)
    {
    case WIFI_AUTH_OPEN:
        ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_OPEN");
        break;
    case WIFI_AUTH_WEP:
        ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WEP");
        break;
    case WIFI_AUTH_WPA_PSK:
        ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA_PSK");
        break;
    case WIFI_AUTH_WPA2_PSK:
        ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA2_PSK");
        break;
    case WIFI_AUTH_WPA_WPA2_PSK:
        ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA_WPA2_PSK");
        break;
    case WIFI_AUTH_WPA2_ENTERPRISE:
        ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA2_ENTERPRISE");
        break;
    case WIFI_AUTH_WPA3_PSK:
        ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA3_PSK");
        break;
    case WIFI_AUTH_WPA2_WPA3_PSK:
        ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA2_WPA3_PSK");
        break;
    default:
        ESP_LOGI(TAG, "Authmode \ttWIFI_AUTH_UNKNOWN");
        break;
    }
}

/* 密码类型 */
static void print_cipher_type(int pairwise_cipher, int group_cipher)
{
    switch (pairwise_cipher)
    {
    case WIFI_CIPHER_TYPE_NONE:
        ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_NONE");
        break;
    case WIFI_CIPHER_TYPE_WEP40:
        ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_WEP40");
        break;
    case WIFI_CIPHER_TYPE_WEP104:
        ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_WEP104");
        break;
    case WIFI_CIPHER_TYPE_TKIP:
        ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_TKIP");
        break;
    case WIFI_CIPHER_TYPE_CCMP:
        ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_CCMP");
        break;
    case WIFI_CIPHER_TYPE_TKIP_CCMP:
        ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_TKIP_CCMP");
        break;
    case WIFI_CIPHER_TYPE_AES_CMAC128:
        ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_AES_CMAC128");
        break;
    case WIFI_CIPHER_TYPE_SMS4:
        ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_SMS4");
        break;
    default:
        ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_UNKNOWN");
        break;
    }

    switch (group_cipher)
    {
    case WIFI_CIPHER_TYPE_NONE:
        ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_NONE");
        break;
    case WIFI_CIPHER_TYPE_WEP40:
        ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_WEP40");
        break;
    case WIFI_CIPHER_TYPE_WEP104:
        ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_WEP104");
        break;
    case WIFI_CIPHER_TYPE_TKIP:
        ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_TKIP");
        break;
    case WIFI_CIPHER_TYPE_CCMP:
        ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_CCMP");
        break;
    case WIFI_CIPHER_TYPE_TKIP_CCMP:
        ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_TKIP_CCMP");
        break;
    default:
        ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_UNKNOWN");
        break;
    }
}

/* 初始化 wifi 为 STA 模式并设置扫描 AP 方式*/
static void wifi_scan(void)
{
    ESP_ERROR_CHECK(esp_netif_init());                      /* 初始化网络协议层 */
    ESP_ERROR_CHECK(esp_event_loop_create_default());       /* 初始化默认事件循环 */
    esp_netif_create_default_wifi_sta();                    /* 创建 wifi STA */

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();         /* wifi 初始默认配置 */
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));                   /* wifi 初始化（切记，只有调用此 API 后才能调用其他 wifi API） */

    uint16_t number = SCAN_LIST_SIZE;
    wifi_ap_record_t ap_info[SCAN_LIST_SIZE];               /* 结构体数组，用于存放所扫描到的 AP 信息 */
    uint16_t ap_count = 0;                                  /* 计算所扫描到的 AP 设备数量 */
    memset(ap_info, 0, sizeof(ap_info));                    /* 清空 ap_info 结构体数组内存 */

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));      /* 设置成 STA 模式 （只有在 STA 或 STA + AP 模式下才能进行 scan）*/
    ESP_ERROR_CHECK(esp_wifi_start());                      /* 开启 wifi */

    /* 
     * 扫描到的所有 AP 会保存在 wifi 驱动动态分配的内存中，会在 esp_wifi_scan_get_ap_records 中释放。
     * 每个通道的最大主动扫描时间和被动扫描时间的值限制为 1500 ms。
     */
    esp_wifi_scan_start(NULL, true);                        /* 开始扫描所有可用 AP, true 代表会阻塞直到扫描完成 */

    ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&number, ap_info));    /* 获取扫描到的 AP 的信息 */
    ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&ap_count));               /* 获取扫描到的 AP 的设备数 */
    ESP_LOGI(TAG, "Total APs scanned = %u", ap_count);

    /* 遍历扫描到的 AP 的信息 */
    for(int i = 0; (i < SCAN_LIST_SIZE) && (i < ap_count); i++)
    {
        ESP_LOGI(TAG, "ssid \t\t%s", ap_info[i].ssid);                  /* AP 账号 */
        ESP_LOGI(TAG, "rssi \t\t%d", ap_info[i].rssi);                  /* AP 信号强度 */
        print_auth_mode(ap_info[i].authmode);                           /* AP 认证模式 */
        if(ap_info[i].authmode != WIFI_AUTH_WEP)
        {
            print_cipher_type(ap_info[i].pairwise_cipher, 
                              ap_info[i].group_cipher);                 /* AP 密码类型 */
        }
        ESP_LOGI(TAG, "Channel \t\t%d\n", ap_info[i].primary);          /* AP 通道 */
    }
}

/* esp32 wifi scan demo */
void esp32_wifi_scan_test(void)
{
    /* 初始化非易失性存储 */
    esp_err_t ret = nvs_flash_init();
    if(ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
    {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ESP_ERROR_CHECK(nvs_flash_init());
    }

    wifi_scan();
}